fix(cli): resolve list/wait projects by repo URL, not directory name (COR-1577) - #137
fix(cli): resolve list/wait projects by repo URL, not directory name (COR-1577)#137juangaitanv wants to merge 2 commits into
Conversation
COR-1577. `corgea list` and standalone `corgea wait` derived the project from the working-directory basename and sent it as an exact `?project=` match. Where the stored name differs — the Bank of Hope case, dir `dotnet-azure-web-tsb` vs project `bohappdev/dotnet-azure-web-tsb` — `list --issues` and `wait` exited 1 and plain `list` silently printed an empty table. Both now resolve the canonical project from the git remote: `GET /api/v1/projects?repo_url=<org/repo>`, discovered upward from the CWD so a subdirectory works too, then query the listing endpoints by the name the backend actually stores. - The backend filters `repo_url__icontains`, so every candidate is re-checked against the whole post-host path. That also guards a pre-COR-1426 backend, which ignores the unknown param and returns ALL projects: none match, and we fall back rather than list a stranger's scans. - Unconfirmed, the query stays exactly what the pre-COR-1577 CLI sent, so an old or not-yet-onboarded backend keeps working. - `--project-name` queries an exact name and skips resolution entirely; `--repo` resolves from a given slug or URL instead of the remote. - An unresolved project with no scans is now an error naming what was tried, instead of an empty table; a confirmed project with no scans still exits 0 so CI polling is unaffected. - The client-side `scan.project == cwd_basename` filter is gone — the server already filtered, and that pass discarded every resolved scan.
0184a26 to
1a543f4
Compare
| ); | ||
| std::process::exit(1); | ||
| } | ||
| format!("{}/project/{}?scan_id={}", config.get_url(), name, scan_id) |
There was a problem hiding this comment.
The canonical names introduced by this PR contain / (the new fixture is bohappdev/dotnet-azure-web-tsb), but this inserts that name into a single URL path segment without encoding it. src/scan.rs:63-74 already documents and enforces the same route contract with urlencoding::encode, specifically because a raw slash routes to the wrong project page. The new test at tests/wait_resolution.rs:93 currently locks in the broken raw URL, so the primary wait result link for COR-1577 will not target the resolved project. Encode the segment and change the test to expect %2F.
| format!("{}/project/{}?scan_id={}", config.get_url(), name, scan_id) | |
| format!( | |
| "{}/project/{}?scan_id={}", | |
| config.get_url(), | |
| urlencoding::encode(name), | |
| scan_id | |
| ) |
| // A scan id plus the project id from the upload response leaves nothing to | ||
| // resolve: everything below keys off the scan, and the id-form URL is | ||
| // already known. | ||
| let resolved = if scan_id.is_some() && project_id.is_some() { |
There was a problem hiding this comment.
This shortcut still makes standalone corgea wait <scan-id> run repo resolution because that CLI path has no project_id. A duplicate/ambiguous repo mapping, malformed /projects payload, or resolver page cap therefore exits in resolve_project_or_exit before line 57 ever checks the explicitly supplied scan. The new wait_with_scan_id_does_not_list_scans test misses this because its /projects stub is successful and it only asserts that /scans was skipped. The scan endpoint already returns both status and project, so make the scan-ID path use that response (honoring an explicit --project-name if supplied) and reserve repo resolution for the scan-less path; add a regression where /projects would fail/ambiguous but wait scan-123 still succeeds.
Fixes COR-1577. Replaces #122, which grew well past the ticket; this is the fix on its own, and the hardening follows in a stacked PR.
The bug
corgea listand standalonecorgea waitderived the project from the working-directory basename and sent it as an exact?project=match. Where the stored name differs — the Bank of Hope case, directorydotnet-azure-web-tsbvs projectbohappdev/dotnet-azure-web-tsb—list --issuesandwaitexited 1, and plainlistsilently printed an empty table.The fix
Resolve the canonical project from the git remote —
GET /api/v1/projects?repo_url=<org/repo>, discovered upward from the CWD so a subdirectory works — then query the listing endpoints by the name the backend actually stores.Three things make it safe on older and partially-onboarded backends:
repo_url__icontains, so a query foracme/apialso returnsacme/api-v2and the nestedmirrors/acme/api. Every candidate is re-checked against the whole post-host path. The same check guards a pre-COR-1426 backend, which ignores the unknown param and returns all projects: none match, so we fall back instead of listing a stranger's scans.determine_project_name), so an old or not-yet-onboarded backend keeps working.Escape hatches:
--project-namequeries an exact name and skips resolution entirely;--reporesolves from a given slug or URL instead of the remote. Both are onlistandwait.Also removes the client-side
scan.project == cwd_basenamefilter — the server already filtered, and that pass discarded every resolved scan.Deliberately not here
Kept out to hold this to the ticket; all of it lands in the stacked follow-up:
/projects(page 1 only today — see COR-1729, which would let the CLI drop both the walk and the re-check)org/repoon two forges/projectsenvelopes/issues(pre-existing)--project-id, SCA selector scoping, argument structsVerification
cargo build,cargo clippy --all-targets(clean),cargo fmt --check, and the full suite underCI=1 GITHUB_ACTIONS=true— 537 tests.16 new e2e tests cover: the canonical name driving
/scansand/issues(asserted on the request the CLI sent, from a checkout namedbuild-123, so a fallback cannot pass); resolution from a subdirectory;--repo; the miss naming the repo with no table; confirmed-empty exiting 0; the legacy fallback name;--project-nameskipping resolution; the JSON envelope preceding the miss;--scan-idskipping resolution; and the post-scancorgea scanpath resolving nothing.Size
429 lines of production code (~340 excluding comments and blank lines), 825 of tests.